const { Service } = require('egg');
const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath = require('ffmpeg-static');
const path = require('path');
const fs = require('fs-extra');
const { v4: uuidv4 } = require('uuid');
const { createCanvas } = require('canvas');
const pMap = require('p-map');

ffmpeg.setFfmpegPath(ffmpegPath);

class VideoService extends Service {
  constructor(ctx) {
    super(ctx);
    ffmpeg.setFfmpegPath(this.config.ffmpeg.ffmpegPath);
    ffmpeg.setFfprobePath(this.config.ffmpeg.ffprobePath);
  }
  /**
   * 提取MP4视频的音频成MP3和创建无音频的MP4
   * @param {string} videoPath - 视频文件路径
   */
  async extractAudioAndCreateSilentVideo(videoPath) {
    const { ctx, app } = this;
    const filename = path.basename(videoPath, path.extname(videoPath));
    const outputDir = path.join(app.baseDir, 'app/public/output', filename);
    await fs.ensureDir(outputDir);

    const mp3Path = path.join(outputDir, `${filename}.mp3`);
    const silentVideoPath = path.join(outputDir, `${filename}_silent.mp4`);

    // 提取音频为MP3
    await new Promise((resolve, reject) => {
      ffmpeg(videoPath)
        .output(mp3Path)
        .noVideo()
        .audioCodec('libmp3lame')
        .on('end', resolve)
        .on('error', reject)
        .run();
    });

    // 创建无音频的视频
    await new Promise((resolve, reject) => {
      ffmpeg(videoPath)
        .output(silentVideoPath)
        .noAudio()
        .on('end', resolve)
        .on('error', reject)
        .run();
    });

    return {
      mp3Path,
      silentVideoPath,
      outputDir,
    };
  }

  /**
   * 将MP3切割成多个WAV片段
   * @param {string} mp3Path - MP3文件路径
   * @param {number} segmentDuration - 每个片段的持续时间（秒）
   */
  async splitAudioToWav(mp3Path, segmentDuration = 5) {
    const { app } = this;
    const filename = path.basename(mp3Path, path.extname(mp3Path));
    const outputDir = path.join(path.dirname(mp3Path), 'wav_segments');
    await fs.ensureDir(outputDir);

    // 获取音频时长
    const duration = await new Promise((resolve, reject) => {
      ffmpeg.ffprobe(mp3Path, (err, metadata) => {
        if (err) return reject(err);
        resolve(metadata.format.duration);
      });
    });

    const segments = [];
    const numSegments = Math.ceil(duration / segmentDuration);

    // 切割音频
    const tasks = Array.from({ length: numSegments }, (_, i) => {
      return async () => {
        const startTime = i * segmentDuration;
        const segmentPath = path.join(outputDir, `segment_${i}.wav`);

        await new Promise((resolve, reject) => {
          ffmpeg(mp3Path)
            .setStartTime(startTime)
            .setDuration(segmentDuration)
            .output(segmentPath)
            .audioCodec('pcm_s16le')
            .toFormat('wav')
            .on('end', resolve)
            .on('error', reject)
            .run();
        });

        segments.push(segmentPath);
      };
    });

    await pMap(tasks, task => task(), { concurrency: 2 });
    return segments;
  }

  /**
   * 生成随机网页特效HTML
   * @param {number} count - 生成的特效数量
   */
  async generateWebEffects(count) {
    const { app } = this;
    const outputDir = path.join(app.baseDir, 'app/public/effects/web');
    await fs.ensureDir(outputDir);

    const effects = [];

    for (let i = 0; i < count; i++) {
      const effectId = uuidv4();
      // 降低透明度到肉眼几乎无法察觉的程度 (0.001-0.005)
      const opacity = (Math.random() * 0.004 + 0.001).toFixed(4);
      const effectType = this._getRandomEffectType();

      let htmlContent = `
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Web Effect ${effectId}</title>
  <style>
    body {
      margin: 0;
      padding: 0;
      overflow: hidden;
      background-color: transparent;
    }
    #effect-container {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      opacity: ${opacity};
    }
  </style>
</head>
<body>
  <div id="effect-container">`;

      // 根据效果类型生成内容
      switch (effectType) {
        case 'particles':
          htmlContent += this._generateParticlesEffect();
          break;
        case 'gradients':
          htmlContent += this._generateGradientsEffect();
          break;
        case 'animation':
          htmlContent += this._generateAnimationEffect();
          break;
        case 'canvas':
          htmlContent += this._generateCanvasEffect();
          break;
      }

      htmlContent += `
  </div>
  <script>
    // 确保透明度保持在指定值
    document.getElementById('effect-container').style.opacity = ${opacity};
  </script>
</body>
</html>`;

      const filePath = path.join(outputDir, `effect_${effectId}.html`);
      await fs.writeFile(filePath, htmlContent);

      effects.push({
        id: effectId,
        path: filePath,
        opacity,
        type: effectType,
        url: `/public/effects/web/effect_${effectId}.html`
      });
    }

    return effects;
  }

  // 私有辅助方法
  _getRandomEffectType() {
    const types = ['particles', 'gradients', 'animation', 'canvas'];
    return types[Math.floor(Math.random() * types.length)];
  }

  _generateParticlesEffect() {
    const particleCount = Math.floor(Math.random() * 100) + 50;
    return `
    <canvas id="particles-canvas"></canvas>
    <script>
      const canvas = document.getElementById('particles-canvas');
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;
      const ctx = canvas.getContext('2d');
      
      const particles = [];
      for (let i = 0; i < ${particleCount}; i++) {
        particles.push({
          x: Math.random() * canvas.width,
          y: Math.random() * canvas.height,
          radius: Math.random() * 5 + 1,
          color: 'hsl(' + Math.random() * 360 + ', 100%, 50%)',
          vx: Math.random() * 2 - 1,
          vy: Math.random() * 2 - 1
        });
      }
      
      function animate() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        
        for (let i = 0; i < particles.length; i++) {
          const p = particles[i];
          
          ctx.beginPath();
          ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
          ctx.fillStyle = p.color;
          ctx.fill();
          
          p.x += p.vx;
          p.y += p.vy;
          
          if (p.x < 0 || p.x > canvas.width) p.vx *= -1;
          if (p.y < 0 || p.y > canvas.height) p.vy *= -1;
        }
        
        requestAnimationFrame(animate);
      }
      
      animate();
    </script>`;
  }

  _generateGradientsEffect() {
    const colors = [
      `hsl(${Math.random() * 360}, 100%, 50%)`,
      `hsl(${Math.random() * 360}, 100%, 50%)`,
      `hsl(${Math.random() * 360}, 100%, 50%)`
    ];

    return `
    <div id="gradient" style="width: 100%; height: 100%;"></div>
    <script>
      const gradientElement = document.getElementById('gradient');
      const colors = ${JSON.stringify(colors)};
      let degree = 0;
      
      function updateGradient() {
        degree = (degree + 0.5) % 360;
        gradientElement.style.background = 
          'linear-gradient(' + degree + 'deg, ' + colors.join(', ') + ')';
        requestAnimationFrame(updateGradient);
      }
      
      updateGradient();
    </script>`;
  }

  _generateAnimationEffect() {
    const shapes = Math.floor(Math.random() * 10) + 5;

    return `
    <div id="animation-container" style="width: 100%; height: 100%; position: relative;"></div>
    <script>
      const container = document.getElementById('animation-container');
      
      for (let i = 0; i < ${shapes}; i++) {
        const shape = document.createElement('div');
        const size = Math.random() * 100 + 50;
        const isCircle = Math.random() > 0.5;
        
        shape.style.position = 'absolute';
        shape.style.width = size + 'px';
        shape.style.height = size + 'px';
        shape.style.backgroundColor = 'hsl(' + Math.random() * 360 + ', 100%, 50%)';
        
        if (isCircle) {
          shape.style.borderRadius = '50%';
        }
        
        shape.style.left = Math.random() * 100 + '%';
        shape.style.top = Math.random() * 100 + '%';
        shape.style.transform = 'translate(-50%, -50%)';
        
        // 添加动画
        shape.animate([
          { transform: 'translate(-50%, -50%) scale(1)', opacity: 0.7 },
          { transform: 'translate(-50%, -50%) scale(1.2)', opacity: 0.3 },
          { transform: 'translate(-50%, -50%) scale(1)', opacity: 0.7 }
        ], {
          duration: 2000 + Math.random() * 3000,
          iterations: Infinity,
          direction: 'alternate'
        });
        
        container.appendChild(shape);
      }
    </script>`;
  }

  _generateCanvasEffect() {
    return `
    <canvas id="canvas-effect"></canvas>
    <script>
      const canvas = document.getElementById('canvas-effect');
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;
      const ctx = canvas.getContext('2d');
      
      let time = 0;
      
      function draw() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        
        const centerX = canvas.width / 2;
        const centerY = canvas.height / 2;
        
        for (let i = 0; i < 10; i++) {
          const radius = 50 + i * 20;
          const hue = (time * 5 + i * 30) % 360;
          
          ctx.beginPath();
          ctx.arc(
            centerX + Math.sin(time * 0.1 + i * 0.1) * radius * 0.2,
            centerY + Math.cos(time * 0.1 + i * 0.1) * radius * 0.2,
            radius,
            0, Math.PI * 2
          );
          ctx.strokeStyle = 'hsla(' + hue + ', 100%, 50%, 0.3)';
          ctx.lineWidth = 2;
          ctx.stroke();
        }
        
        time += 0.05;
        requestAnimationFrame(draw);
      }
      
      draw();
    </script>`;
  }


  /**
   * 生成随机视频特效
   * @param {number} count - 生成的特效数量
   */
  async generateVideoEffects(count) {
    const { app } = this;
    const outputDir = path.join(app.baseDir, 'app/public/effects/video');
    await fs.ensureDir(outputDir);

    const effects = [];

    for (let i = 0; i < count; i++) {
      const effectId = uuidv4();
      const opacity = (Math.random() * 0.004 + 0.001).toFixed(3); // 降低透明度到肉眼几乎无法察觉的程度 (0.001-0.004)
      const duration = 10; // 10秒
      const width = 1280;
      const height = 720;
      const fps = 30;

      // 创建临时图片目录
      const framesDir = path.join(outputDir, `frames_${effectId}`);
      await fs.ensureDir(framesDir);

      // 生成每一帧
      const frameCount = duration * fps;
      const effectType = this._getRandomEffectType();

      // 生成帧
      for (let frame = 0; frame < frameCount; frame++) {
        const canvas = createCanvas(width, height);
        const ctx = canvas.getContext('2d');

        // 透明背景
        ctx.clearRect(0, 0, width, height);

        // 根据不同特效类型绘制
        switch (effectType) {
          case 'particles':
            this._drawParticlesFrame(ctx, frame, width, height, opacity);
            break;
          case 'gradients':
            this._drawGradientFrame(ctx, frame, width, height, opacity);
            break;
          case 'animation':
            this._drawAnimationFrame(ctx, frame, width, height, opacity);
            break;
          case 'canvas':
            this._drawCanvasFrame(ctx, frame, width, height, opacity);
            break;
        }

        // 保存帧
        const frameFile = path.join(framesDir, `frame_${frame.toString().padStart(6, '0')}.png`);
        const buffer = canvas.toBuffer('image/png');
        await fs.writeFile(frameFile, buffer);
      }

      // 使用ffmpeg将帧合成视频，并设置极低的透明度
      const outputPath = path.join(outputDir, `effect_${effectId}.mp4`);

      await new Promise((resolve, reject) => {
        ffmpeg()
          .input(path.join(framesDir, 'frame_%06d.png'))
          .inputFPS(fps)
          .output(outputPath)
          .outputOptions([
            '-c:v libx264',
            '-pix_fmt yuva420p', // 启用Alpha通道
            '-crf 23'
            // 不再需要透明度过滤器，因为透明度已经在绘制帧时设置
          ])
          .on('end', resolve)
          .on('error', reject)
          .run();
      });

      // 清理临时帧文件
      await fs.remove(framesDir);

      effects.push({
        id: effectId,
        path: outputPath,
        opacity,
        type: effectType,
        url: `/public/effects/video/effect_${effectId}.mp4`
      });
    }

    return effects;
  }


  // 视频特效帧绘制方法
  _drawParticlesFrame(ctx, frame, width, height, opacity) {
    const particleCount = 10;
    const time = frame / 30; // 基于帧的时间

    for (let i = 0; i < particleCount; i++) {
      const x = width * (0.1 + 0.8 * (i % 10) / 10 + Math.sin(time * 0.5 + i) * 0.05);
      const y = height * (0.1 + 0.8 * Math.floor(i / 10) / 10 + Math.cos(time * 0.5 + i) * 0.05);
      const radius = 2 + Math.sin(time + i) * 0.5;

      ctx.beginPath();
      ctx.arc(x, y, radius, 0, Math.PI * 2);
      ctx.fillStyle = `hsla(${(time * 20 + i * 3) % 360}, 100%, 10%, ${opacity})`;
      ctx.fill();
    }
  }

  _drawGradientFrame(ctx, frame, width, height, opacity) {
    const time = frame / 30;
    const gradient = ctx.createLinearGradient(0, 0, width, height);

    // 使用更低的亮度和饱和度，以及更低的透明度
    gradient.addColorStop(0, `hsla(${(time * 20) % 360}, 50%, 10%, ${opacity})`);
    gradient.addColorStop(0.5, `hsla(${(time * 20 + 120) % 360}, 50%, 10%, ${opacity})`);
    gradient.addColorStop(1, `hsla(${(time * 20 + 240) % 360}, 50%, 10%, ${opacity})`);

    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, width, height);
  }

  _drawAnimationFrame(ctx, frame, width, height, opacity) {
    const time = frame / 30;
    const shapes = 10;

    for (let i = 0; i < shapes; i++) {
      const size = width * (0.1 + 0.05 * Math.sin(time + i));
      const x = width / 2 + Math.cos(time * 0.2 + i) * width * 0.3;
      const y = height / 2 + Math.sin(time * 0.2 + i) * height * 0.3;

      ctx.save();
      ctx.translate(x, y);
      ctx.rotate(time * 0.1 + i);

      if (i % 2 === 0) {
        // 矩形
        ctx.fillStyle = `hsla(${(time * 20 + i * 36) % 360}, 100%, 50%, ${opacity})`;
        ctx.fillRect(-size / 2, -size / 2, size, size);
      } else {
        // 圆形
        ctx.beginPath();
        ctx.arc(0, 0, size / 2, 0, Math.PI * 2);
        ctx.fillStyle = `hsla(${(time * 20 + i * 36) % 360}, 100%, 50%, ${opacity})`;
        ctx.fill();
      }

      ctx.restore();
    }
  }

  _drawCanvasFrame(ctx, frame, width, height, opacity) {
    const time = frame / 30;

    // 波浪效果
    ctx.beginPath();
    ctx.strokeStyle = `hsla(${(time * 30) % 360}, 50%, 10%, ${opacity})`; // 降低饱和度和亮度
    ctx.lineWidth = 1; // 减小线条宽度
    for (let x = 0; x < width; x += 20) {
      const y = height / 2 + Math.sin(x * 0.01 + time) * 20; // 减小振幅
      if (x === 0) {
        ctx.moveTo(x, y);
      } else {
        ctx.lineTo(x, y);
      }
    }
    ctx.stroke();

    // 辅助线
    for (let i = 0; i < 3; i++) { // 减少辅助线数量
      ctx.beginPath();
      ctx.strokeStyle = `hsla(${(time * 30 + i * 30) % 360}, 50%, 10%, ${opacity})`; // 降低饱和度和亮度
      ctx.lineWidth = 0.5; // 减小线条宽度
      for (let x = 0; x < width; x += 20) {
        const offset = 25 * i; // 减小偏移量
        const y = height / 2 + Math.sin(x * 0.01 + time + i * 0.5) * 20 + offset; // 减小振幅
        if (x === 0) {
          ctx.moveTo(x, y);
        } else {
          ctx.lineTo(x, y);
        }
      }
      ctx.stroke();
    }
  }
}

module.exports = VideoService; 